package blockchain

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"time"
)


var BlockChains = make([]BlockChain, 0)
var Transactions = make([]Transaction, 0)
var Nodes = make([]string, 0)

type FullBlockChains struct {
	BlockChains []BlockChain `json:"chains"`
	Length int `json:"length"`
}

func init()  {
	NewBlockChain(100, "none")
}
//交易体
type Transaction struct {
	Sender string `json:"sender"` //交易者
	Recipient string `json:"recipient"` //接受者
	Amount float64 `json:"amount"` //交易的金额
}

//区块
type BlockChain struct {
	Index int64                 //索引
	Timestamp time.Time         //时间戳
	Transactions []Transaction //交易的信息
	WorkProof int64                //工作量证明
	PreHash string              //上一个区块的hash值
}

//新建一个交易体
func NewTransaction(sender, recipient string, amount float64)  {
	AddTransaction(Transaction{
		Sender: sender,
		Recipient: recipient,
		Amount: amount,
	})
}

//添加一个交易体
func AddTransaction(transaction Transaction)  {
	Transactions = append(Transactions, transaction)
}

//新建一个区块
func NewBlockChain(workProof int64, preHash string) BlockChain {
	if preHash == "" {
		preHash = GenerateHash(BlockChains[int64(len(BlockChains) - 1)])
	}
	 blockChain := BlockChain{
		Index: int64(len(BlockChains)),
		Timestamp: time.Now(),
		Transactions: Transactions,
		WorkProof: workProof,
		PreHash: preHash,
	}

	BlockChains = append(BlockChains, blockChain)
	Transactions = make([]Transaction, 0)

	return blockChain
}
//生成一个hash
func GenerateHash(chain BlockChain) string  {
	data, err := json.Marshal(chain)
	if err != nil {
		log.Println(err.Error())
		return ""
	}
	hash := sha256.New()
	hash.Write(data)
	strBytes := hash.Sum(nil)

	return hex.EncodeToString(strBytes)
}

//获取最后一个区块
func LastBlockChain()BlockChain  {
	return BlockChains[len(BlockChains) - 1]
}

func WorkProof(lastProof int64) int64  {
	proof := int64(0)
	for !VerifyWorkProof(lastProof, proof) {
		proof++
	}
	fmt.Println()
	fmt.Println(proof)
	return proof
}

//验证工作量证明
func VerifyWorkProof(lastProof, currentProof int64) bool  {
	proofStr := fmt.Sprintf("%d%d", lastProof, currentProof)

	hash := sha256.New()
	hash.Write([]byte(proofStr))
	bytes := hash.Sum(nil)
	hashCode := hex.EncodeToString(bytes)
	fmt.Printf("\r%s", hashCode)
	if hashCode[0:4] == "0000" {
		return true
	}

	return false
}

//注册节点 "http://127.0.0.1:300"
func RegisterNode(node string)  {
	parse, err := url.Parse(node)
	if err != nil {
		log.Println(err.Error())
		return
	}
	Nodes = append(Nodes, parse.Host)
}

//验证区块链的是否是合法的
func VerifyChains(chains []BlockChain) bool  {
	lastBlock := chains[0]
	index := 1
	for index < len(chains) {
		currentBlock := chains[index]
		if currentBlock.PreHash != GenerateHash(lastBlock) || !VerifyWorkProof(lastBlock.WorkProof, currentBlock.WorkProof) {
			return false
		}
		index++
		lastBlock = currentBlock
	}

	return true
}

//实现共识，多个节点如何获取最长最有效的区块链
func ResolveConflictFromNodes() bool  {
	maxLength := len(BlockChains)
	newChains := make([]BlockChain, 0)
	for _, node := range Nodes {
		resp, err := http.Get(fmt.Sprintf("http://%s/blockChains", node))
		if err != nil {
			log.Println(err.Error())
			continue
		}
		contentBytes, err := io.ReadAll(resp.Body)
		resp.Body.Close()
		allChains := FullBlockChains{}
		json.Unmarshal(contentBytes, &allChains)
		if allChains.Length > maxLength && VerifyChains(allChains.BlockChains) {
			maxLength = allChains.Length
			newChains = allChains.BlockChains
		}
	}
	if len(newChains) > 0 {
		BlockChains = newChains
		return true
	}

	return false
}